﻿/**
 * 菜单模块 - 核心模块 -- 可选
 * 菜单模块依赖于事件模块，所有方法都在事件模块注册的事件当中调用
 * 
 * 左键快捷菜单、右键菜单，
 * 左键：超链接，图片，选中文字
 * 右键：表格。
 */
(function(E, $){
var Consts = E.consts,
	isShow = false,
	timeids={mouseover:0, mouseout:0, tidHidePanel:0},
	Event = E.mod("Event");

// 鼠标或键盘按下时隐藏菜单
Event.bind('keydown', function(){
	clearTimeout(timeids['tidHidePanel']);
	timeids['tidHidePanel'] = setTimeout(function(){
		E.hidePanel();
	}, 1000);
});
Event.bind('mousedown', function(){
	E.hidePanel();
});


E.mod("Menu", {
	add: function(type, obj){
		Menu.add( type, obj );
	},
	
	set: function( e, type ){
		Menu.type = type;
		return Menu.set(e);
	},
	
	hide: function(){
		Menu.hide( );
	},
	
	isShow: function( Plugin ){
		if( Plugin ){
			var menu = $("div[id^=jqe-" + Plugin.name+"]");
			return menu.size() && menu.is(':visible') &&  E.eid == menu.attr('eid');
		}else{
			return isShow;
		}
	}
});

//菜单私有对象
var Menu = {
	//菜单类型有 contextmenu / click 两种
	type: '',
	
	//菜单 jQuery 对象
	menu: null,
	
	//菜单对象集合
	click_objs: [],
	contextmenu_objs: [],
	mouseup_objs: [],
	
	/**
	 * 添加一个菜单
	 * @param type string "contextmenu|click"
	 * 		菜单类型
	 * @param obj object
	 * 		菜单对象，包含几个固定的方法，{check:function(), build: function(), action_*: function()}
	 */
	add: function(type, obj){
		var self = this;
		if( !self[type+'_objs'] ){
			self[type+'_objs'] = [];
		}
		self[type+'_objs'].push(obj);
	},
	
	/**
	 * 设置菜单，由内容编辑区域事件触发
	 * @param object e
	 * 		浏览器事件对象
	 */
	set: function( e ){
		var self=this,
			menuPlugin = null,
			menu = null,
			objs = self[ self.type +'_objs'],
			id,
			Selection = E.mod('Selection'),
			cursorElement = null,
			cursorText = '';
		
		if( Selection ){
			cursorText = ''+Selection.getText( );
			cursorElement = Selection.getElement( );
			
			//注意，有个例外
			//在FF下，当鼠标点击图片时，如果图片存在title属性，
			//则cursorText会记录图片的alt||title值，alt优先于title，
			//顾这种情况下，需要使用cursorElement覆盖cursorText。
			if( typeof cursorElement === 'object' && $.nodeName(cursorElement, 'img') ){
				cursorText = cursorElement;
			}
		}
		
		try{
			for(var i in objs){
				menuPlugin = objs[i];
				//逐个对象判断，调用它的check()方法
				
				if( menuPlugin.check( cursorText || cursorElement, e ) ){
					//检查通过，则显示菜单，首次需要调用build()方法构建
					id = 'jqe-'+ self.type +'-'+i;
					
					// 先隐藏当前已经显示的菜单
					self.hide();
					
					menu = self.build( id, menuPlugin, cursorElement );
					break;
					
					// 注：同时只能显示一个菜单，当有一个菜单符合条件时，既break跳出
				}
			}
		 }catch(e){
			var title = menuPlugin.title || '未知';
			E.log('error', '菜单插件'+title+'遇到错误，'+e.description+'，menuPlugin.check: '+menuPlugin.check);
		}
		
		//显示菜单时，return false，禁止事件冒泡
		if( menu ){
			self.menu = menu;
			self.setPosition(e);
			self.show();
			E.log("run", "显示菜单："+ menuPlugin.title);
			return false;
		}else{
			return true;
		}
	},
	
	/**
	 * 构建菜单
	 * @param string id
	 * @param menuPlugin object
	 */
	build: function( id, menuPlugin, cursorElement ){
		var self = this,
			html = [],
			menu = null,
			menuBody,
			option = E.get('option'),
			Lang = E.lang(option.lang),
			Icons = E.icon( option.skin ),
			title,
			Plugin,
			plugins = {};
			
		
		// 诡异问题 2011-05-04 21:47 潘雪鹏
		// menubody = menuPlugin.getHtml(); 不能放到上面的var 当中，
		// 否则不能正确得到 menuPlugin.getHtml() 的返回值
		
		menubody = menuPlugin.getHtml( cursorElement );
		
		
		if( typeof menubody === 'string' ){
			html.push('<div id="'+id+'" class="jqe-menu" eid="'+E.eid+'">');
			html.push( menubody );
			html.push('</div>');
			
		}else if( typeof menubody === 'object' && menubody.html ){
			if( menubody.className ){
				html.push('<div id="'+id+'" class="jqe-menu '+ menubody.className +'" eid="'+E.eid+'">');
			}else{
				html.push('<div id="'+id+'" class="jqe-menu">');
			}
			html.push(menubody.html);
			html.push('</div>');
			
		}else if( typeof menubody === 'object' ){
			html.push('<div id="'+id+'" class="jqe-menu" eid="'+E.eid+'">');
			html.push('<ul class="jqe-menu-list jqe-'+ option.skin +'">');
			for( name in menubody ){
				if( "-" === name.substr(0,1) ){
					html.push('<li menutype="1" class="jqe-menu-separator"></li>');
					continue;
				}
				
				title = Lang[name];
				if( title && typeof title == "object" ){
					title = title.title;
				}
				
				html.push('<li menutype="1" menuname="'+name+'" ');
				if( !menubody[name] ){
					html.push(' class="jqe-menu-disabled"');
				}
				html.push('><a name="'+name+'" href="jqe:menu-'+name+'" onclick="return false">');
				html.push('<span class="jqe-menu-icon '+name);
				
				if(!Icons[name]){
					html.push(' jqe-menu-noicon');
				}
				html.push('"></span>');
				html.push('<span class="jqe-menu-text">'+title+'</span>');
				
				if(  menubody[name] == 2 || typeof menubody[name] === "object" ){
					html.push('<span class="jqe-shortcut-key"></span>');
					html.push('<span class="jqe-menu-arrow"></span>');
					html.push('</a><div class="jqe-menu jqe-submenu">');
					
					if(menubody[name] == 2){
						Plugin = E.plugin(name);
						if(Plugin){
							html.push(Plugin.panelHtml());
							plugins[name] = Plugin;
						}else{
							// log
						}
					}else{
						html.push('<ul class="jqe-menu-list jqe-'+ option.skin +'">');
						for( subname in menubody[name] ){
							title = Lang[subname];
							if( title && typeof title == "object" ){
								title = title.title;
							}
							html.push('<li menutype="2" ');
							if( "-" === subname.substr(0,1) ){
								html.push(' class="jqe-menu-separator">');
							}else{
								html.push('><a name="'+subname+'"><span class="jqe-menu-icon '+subname);
								if(!Icons[subname]){
									html.push(' jqe-menu-noicon');
								}
								html.push('"></span><span class="jqe-menu-text">'+title+'</span></a>');
							}
							html.push('</li>');
						}
						html.push('</ul>');
						html.push('<div class="jqe-menu-vertical-separator"></div>');
					}
					html.push('</div>');
				}else{
					html.push('</a>');
				}
				html.push('</li>');
			}
			html.push('</ul>');
			html.push('<div class="jqe-menu-vertical-separator"></div>');
			html.push('</div>');
		}
		
		
		$("body").append( html.join('') );
		menu = $('#'+id);
		
		if( typeof menuPlugin.callback === "function" ){
			menuPlugin.callback(menu);
		}
		/*
		if( typeof menuPlugin.timeout === 'number' && menuPlugin.timeout>=2000 ){
			setTimeout(function(){
				self.hide();
			}, menuPlugin.timeout);
		}
		*/
		//给菜单项绑定点击事件
		//点击菜单项触发 Menu.action( target ) 方法
		menu.click(function( e ){
			var target = $(e.target);
			if( target.closest('li').hasClass('jqe-menu-disabled') ){
				return false;
			}
			
			return self.action( target.closest('a[name]'), e );
		}).mousedown(function(e){
			var target = $(e.target);
			// 提示：2011-05-13 潘雪鹏
			// 防止点击Input后不能使其获取焦点
			// 所以在input上mousedowns时不能返回false
			// 不需要考虑click的事件返回true或false
			if( target.is(':input') ){return true;}
			return false;
		}).mouseover(function(e){
			var pluginName = $(this).attr("id").replace(/(^jqe-|-\d\d?$)/g, "");
			$("#"+E.eid+"-"+pluginName).addClass("jqe-button-hover");
		});
		
		menu.find('li').hover(
			function(){
				var o = $(this);
				var submenu = o.children('div.jqe-submenu');
				
				if( o.attr('menutype') == '1' ){
					menu.find('div.jqe-submenu').hide();
				}
				o.children('a').addClass('hover');
				
				if( submenu.size() ){
					submenu.show();
					
					var maxTop = $(document).scrollTop() + $(window).height();
					var submenuBottom = submenu.height() + o.offset().top;
					if( submenuBottom > maxTop ){
						var _top = maxTop - submenuBottom - 20;
						submenu.css('top', _top);
					}
				}
			},
			function(){
				var o = $(this);
				o.find('a.hover').removeClass('hover');
			}
		);
		
		for(var name in plugins){
			(function(Plugin){
				if( typeof Plugin.one === "function" ){
					var li = menu.find('li[menuname='+name+']'),
						submenu = li.find('.jqe-submenu');
						
					li.click(function(e){
						var target = $(e.target);
						return false;
					});
					Plugin.one(submenu, Plugin);
					submenu.click(function( e ){
						var target = $(e.target),
							html = Plugin.action( $(e.target), submenu, Plugin );
						if( html ){
							Plugin.pasteHTML( html );
							E.monitor(Plugin.name);
							self.hide();
						}
					});
				}
			})(plugins[name]);
		}
		
		return menu;
	},
	
	/**
	 * 菜单项点击触发的方法
	 * 再由此方法根据事件来源，判断调用相应对象的方法
	 * @param jQuery target 事件来源对象
	 */
	action: function(target, e){
		var self = this,
			name = target.attr('name');
			
		if( name && E.action( name, e ) ){
			self.menu.hide();
		}
		
		// 如果return false 会导致点击快捷菜单打开链接按钮失效
		// 所以需要判断一下，如果来自快捷菜单则return true
		// 否则return false
		if( target.closest('.jqe-shortcut-menu').size() ){
			return true;
		}else{
			return false;
		}
	},
	
	//显示菜单
	show: function(){
		var self=this;
		
		self.menu.show();
		if( Consts.IE6 ){
			var height = self.menu.height();
			self.menu.find('.jqe-menu-vertical-separator').height( height );
		}
		isShow = true;
	},
	
	//隐藏菜单
	hide: function(){
		// 菜单隐藏时，即时删除
		$('.jqe-menu').unbind('click').remove();
		$('.jqe-button-hover').removeClass('jqe-button-hover');
		isShow = false;
	},
	
	//设置菜单的显示位置
	setPosition: function( e ){
		var self=this, left, top, 
			iframe = E.get('iframe'),
			offset = $(iframe).offset(),
			target = $(e.target),
			scrollTop = $(document).scrollTop() || document.documentElement.scrollTop,
			jqeBtn = target.closest('.jqe-button');
			
		self.menu.removeAttr('plugin');
		if( jqeBtn.size() ){
			// target 来自编辑器工具栏按钮点击对象
			target = target.closest('.jqe-button');
			offset = target.offset();
			left = offset.left;
			top = offset.top + target.height() + 1;
			
			target.addClass('jqe-button-hover');
			
			self.menu.attr('plugin', jqeBtn.attr("id"));
		}else if(e.button === 2 || target.is('img')){
		// target 来自编辑器内容区域被鼠标右键点击的对象 或是图片对象
			left = e.clientX + offset.left;
			top = e.clientY + offset.top;
			
			if( self.type == 'contextmenu' ){
				left += 10;
				top += 10;
			}else if( self.type == 'mouseup' ){
				top += 10;
			}
			
			// 注意不能超出窗口下边界
			var maxTop = scrollTop + $(window).height() - self.menu.height() - 20;
			top = top < maxTop ? top : maxTop;
		}else{
			// 左键点击，一般是快捷菜单
			left = e.clientX + offset.left;
			top = e.clientY + offset.top + 20;
			
			var maxTop = scrollTop + $(window).height() - self.menu.height();
			// 菜单定位到对象的下面或上面比较合适，否则会遮挡后面的文字
			if( top > maxTop ){
				top = maxTop - 50;
			}
		}
		
		//如果 body 是 relatiove 定位，很可能导致面板定位不准确。
		//理想情况是body居中，则计算一下body 和 //窗口宽度差然后除以2，如果小于0，则用left减去即可
		if($("body").css("position") === "relative"){
			var _W = ($(window).width() - $("body").width())/2;
			if ( _W>0 ) left -= _W;
		}
		
		
		return self.menu.css({left:left, top:top});
	}
}

})(jQEditor, jQuery);